﻿namespace BattleShip.BattleShipBot
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;

    public class BotForFoundedShip : IAttacker
    {
        private const int MaxShipSize = 4;
        private int firstXCoordinate;
        private int secondXCoordinate;
        private string lastAttackPosstion;
        private Queue<string> toLeft;
        private Queue<string> toRight;
        private Queue<string> toUp;
        private Queue<string> toDown;
        private SideForAttack sideForAttack;
        private Playground playground;

        public BotForFoundedShip(string coordinates, Playground enemyPlayGroundFromBot)
        {
            lastAttackPosstion = coordinates;
            string[] coordinatesArr = coordinates.Split(' ');
            this.firstXCoordinate = int.Parse(coordinatesArr[0]);
            this.secondXCoordinate = int.Parse(coordinatesArr[1]);
            FullTheQueues(this.firstXCoordinate, this.secondXCoordinate);
            sideForAttack = SideForAttack.Left;
            playground = enemyPlayGroundFromBot;
        }

        public string Attack()
        {
            string position = string.Empty;

            if (sideForAttack == SideForAttack.Left)
            {
                if (AttackIsAvailable(toLeft))
                {
                    position = toLeft.Dequeue();
                }
                else
                {
                    sideForAttack = SideForAttack.Right;
                }
            }

            if (sideForAttack == SideForAttack.Right)
            {
                if (AttackIsAvailable(toRight))
                {
                    position = toRight.Dequeue();
                }
                else
                {
                    sideForAttack = SideForAttack.Up;
                }
            }

            if (sideForAttack == SideForAttack.Up)
            {
                if (AttackIsAvailable(toUp))
                {
                    position = toUp.Dequeue();
                }
                else
                {
                    sideForAttack = SideForAttack.Down;
                }
            }

            if (sideForAttack == SideForAttack.Down)
            {
                if (AttackIsAvailable(toDown))
                {
                    position = toDown.Dequeue();
                }
                else
                {
                    throw new ArgumentException("Problem in Method for Attack");
                }
            }

            this.lastAttackPosstion = position;
            return position;
        }

        public void GetReportForAttackPosition(Dictionary<string, StatmentOfPositionInMatrix> returnStat)
        {
            foreach (var coordinate in returnStat)
            {
                if (returnStat[coordinate.Key] == StatmentOfPositionInMatrix.Hitted)
                {
                    playground.ChangeMatrixStatment(new string[] { coordinate.Key }, StatmentOfPositionInMatrix.Hitted);
                }
                else if (returnStat[coordinate.Key] == StatmentOfPositionInMatrix.Destroyed)
                {
                    List<string> hittedPosition = new List<string>();
                    foreach (var destroyedCoordinate in returnStat)
                    {
                        hittedPosition.Add(destroyedCoordinate.Key);
                    }

                    playground.ChangeMatrixStatment(hittedPosition.ToArray(), StatmentOfPositionInMatrix.Destroyed);
                }
                else if (returnStat[coordinate.Key] == StatmentOfPositionInMatrix.Empty)
                {
                    this.sideForAttack++;
                }
            }
        }

        private void FullTheQueues(int xCoordinate, int yCoordinate)
        {
            if (xCoordinate < 0 || xCoordinate > 9 || yCoordinate < 0 || yCoordinate > 9)
            {
                throw new IndexOutOfRangeException("Values of Coordinates are out of matrix size!");
            }

            toLeft = new Queue<string>();
            toRight = new Queue<string>();
            toUp = new Queue<string>();
            toDown = new Queue<string>();

            // attack to left
            for (int i = 1; i < MaxShipSize; i++)
            {
                if (xCoordinate - i >= 0)
                {
                    int newXCoordinate = xCoordinate - i;
                    string coordinate = newXCoordinate + " " + yCoordinate;
                    toLeft.Enqueue(coordinate);
                }
                else
                {
                    break;
                }
            }

            // attack to right
            for (int i = 1; i < MaxShipSize; i++)
            {
                if (xCoordinate + i <= 9)
                {
                    int newXCoordinate = xCoordinate + i;
                    string coordinate = newXCoordinate + " " + yCoordinate;
                    toRight.Enqueue(coordinate);
                }
                else
                {
                    break;
                }
            }

            // attack to down
            for (int i = 1; i < MaxShipSize; i++)
            {
                if (yCoordinate + i <= 9)
                {
                    int newYCoordinate = yCoordinate + i;
                    string coordinate = xCoordinate + " " + newYCoordinate;
                    toDown.Enqueue(coordinate);
                }
                else
                {
                    break;
                }
            }

            // attack to up
            for (int i = 1; i < MaxShipSize; i++)
            {
                if (yCoordinate - i >= 0)
                {
                    int newYCoordinate = yCoordinate - i;
                    string coordinate = xCoordinate + " " + newYCoordinate;
                    toUp.Enqueue(coordinate);
                }
                else
                {
                    break;
                }
            }
        }

        private bool AttackIsAvailable(Queue<string> queue)
        {
            if (queue.Count <= 0)
            {
                return false;
            }
            if (playground.IsPositionVisited(queue.Peek()))
            {
                return false;
            }

            return true;
        }
    }
}
